package com.mgg.gateway.filter;

import com.mgg.gateway.service.AccessLogService;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

/**
 * 权限拦截器
 * @Author: lijun
 * @Date: 2018/9/6 15:11
 */
@Component
public class SetUserIdToHeaderFilter extends ZuulFilter{

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Autowired
    private AccessLogService accessLogService;

    @Autowired
    @Qualifier("poolTaskExecutor")
    private Executor executor;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication instanceof OAuth2Authentication) {
            return true;
        }
        saveAccessRecord(RequestContext.getCurrentContext().getRequest(), null);
        return false;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String header = ctx.getRequest().getHeader("Authorization");
        if (header == null || !header.startsWith("Bearer ")) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            ctx.setResponseBody("{\"result\":\"请求头中无token信息!\"}");
            ctx.getResponse().setContentType("application/json;charset=UTF-8");
        } else {
            String token = StringUtils.substringAfter(header, "Bearer ");
            TokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
            OAuth2Authentication authentication = redisTokenStore.readAuthentication(token);
            if (authentication == null) {
                ctx.setSendZuulResponse(false);
                ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
                ctx.setResponseBody("{\"result\":\"accessToken为空!\"}");
                ctx.getResponse().setContentType("application/json;charset=UTF-8");
            } else{
                String userId = authentication.getName();
                ctx.addZuulRequestHeader("user_id", userId);
                saveAccessRecord(RequestContext.getCurrentContext().getRequest(), userId);
            }
        }
        return null;
    }

    /**
     * 保存接口访问记录
     * @param request
     * @param userId
     */
    private void saveAccessRecord(HttpServletRequest request, String userId) {
        String url = request.getRequestURI();
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        String deviceId = request.getHeader("deviceId");
        String appVersion = request.getHeader("appVersion");
        String platform = request.getHeader("platform");
        String phoneModel = request.getHeader("phoneModel");

        Map<String, String> map = new HashMap<>();
        map.put("time", time);
        map.put("userId", userId);
        map.put("deviceId", deviceId);
        map.put("platform", platform);
        map.put("appVersion", appVersion);
        map.put("phoneModel", phoneModel);
        map.put("ip", getIpAddress(request));

        CompletableFuture
                .runAsync(() -> {
                    accessLogService.saveAccessRecord(url,map,request.getParameterMap());
                }, executor);
    }

    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
